# == Schema Information
# Schema version: 33
#
# Table name: regalos
#
#  id                 :integer(11)   not null, primary key
#  remitente_id       :integer(11)   
#  invitado_id        :integer(11)   
#  email_remitente    :string(255)   
#  email_invitado     :string(255)   
#  tipo_regalo_id     :integer(11)   
#  plantilla_id       :integer(11)   
#  nick_mostrado      :string(255)   
#  telefono_mostrado  :string(255)   
#  poblacion_mostrado :string(255)   
#  edad_mostrado      :string(255)   
#  sexo_mostrado      :string(255)   
#  mostrar_email      :boolean(1)    
#  mostrar_avatar     :boolean(1)    
#  created_at         :datetime      
#  fecha_terminado    :datetime      
#  fecha_notificado   :datetime      
#  state              :string(255)   
#  texto              :text          
#

class Regalo < ActiveRecord::Base
  belongs_to :remitente, :class_name => 'Usuario', :foreign_key => :remitente_id
  belongs_to :invitado, :class_name => 'Usuario', :foreign_key => :invitado_id
  belongs_to :tipo_regalo
  belongs_to :plantilla

  has_many :eventos
  has_many :mensajes

  validates_presence_of :plantilla_id, :tipo_regalo_id, :texto

  validates_email_format_of :email_invitado, :message => 'Tiene un formato incorrecto', 
                            :if => lambda { |record| record.invitado.nil? || !record.email_invitado.blank?}

  validates_email_format_of :email_remitente, :message => 'Tiene un formato incorrecto', 
                            :if => lambda { |record| !record.email_remitente.nil?}

  def validate
    if (!remitente_id.blank? && !invitado_id.blank?)
      errors.add("email_invitado", "no puedes mandarte un regalo a ti mismo")  if (remitente_id == invitado_id)
    elsif (!remitente_id.blank? && !email_invitado.blank?)
      usuario = Usuario.find_by_email(email_invitado)
      id = usuario.id if usuario
      errors.add("email_invitado", "no puedes mandarte un regalo a ti mismo")  if (remitente_id == id)
    end      

    if (invitado_id == nil and email_invitado.blank?)
      errors.add("email_invitado", "indica el usuario o el email del invitado") 
    elsif (invitado_id != nil and !email_invitado.blank?)  
      errors.add("email_invitado", "indica el usuario o el mail del invitado, no ambos")
    end
    
    errors.add("email_remitente", "indica tu email") if (remitente_id == nil and email_remitente.blank?) 
    errors.add("email_remitente", "el email ya está registrado en el sistema") if (email_remitente && Usuario.find_by_email(email_remitente))
    errors.add("email_remitente", "remitente y destino no pueden ser el mismo") if (!email_remitente.blank? && email_remitente == email_invitado)
  end
  
  after_create :crea_evento_nuevo_regalo
  after_update :crea_evento_aceptado_rechazado

  before_save :email_invitado?
  
  # Comprueba que el email pueda pertenecer ya a un usuario del sistema
  # Si es asi, le asignamos el regalo al usuario y no al email
  
  def email_invitado?
    if(usuario = Usuario.find_by_email(self.email_invitado))
        self.email_invitado = nil
        self.invitado_id = usuario.id
    end
  end
  
  #
  # Logica del modelo
  #

  acts_as_state_machine :initial => :pendiente  
  state :pendiente  
  state :aceptado  
  state :rechazado  
  state :expirado

  event :aceptar do  
    transitions :from => :pendiente, :to => :aceptado  

  end

  event :rechazar do  
    transitions :from => :pendiente, :to => :rechazado  
  end

  event :expirar do
    transitions :from => :pendiente, :to => :expirado
  end  

  # Metodo que genera el hash_code para el remitente que no es usuario de la aplicacion
  def hash_code_remitente
    if invitado.nil?
      "#{id}-#{Digest::MD5.hexdigest("#{id} + #{email_remitente} + #{email_invitado} + #{created_at}")[0..6]}"
    else
      "#{id}-#{Digest::MD5.hexdigest("#{id} + #{email_remitente} + #{invitado.email} + #{created_at}")[0..6]}"
    end
  end

  # Metodo que genera el hash_code para el invitado que no es usuario de la aplicacion
  def hash_code_invitado
    if remitente.nil?
      "#{id}-#{Digest::MD5.hexdigest("#{id} + #{email_invitado} + #{email_remitente} + #{created_at}")[0..6]}"
    else
      "#{id}-#{Digest::MD5.hexdigest("#{id} + #{email_invitado} + #{remitente.email} + #{created_at}")[0..6]}"
    end
  end

  # Es el hash_code del remitente o del invitado valido?
  def self.es_valido?(rol, hash) #rol => [remitente, invitado]
    return false if hash == nil
    id = hash.split('-')[0].to_i
    regalo = Regalo.find(:first, :conditions => ["id = ?", id])
    return false if regalo == nil
    eval "regalo.hash_code_#{rol} == hash"
  end

  # Devuelve el último mensaje
  def ultimo_mensaje
    self.mensajes[-1] if mensajes.length != 0
  end
   
  # Método que devuelve los tres más regalado en esta semana. Si aún
  # no existen tres, obtendremos los tres de la semana anterior.
  def self.lo_mas_regalado
    regalos = find(:all, :select => 'COUNT(*) as cuenta, tipo_regalo_id', :group => 'tipo_regalo_id', 
                   :conditions => ["created_at > ?", Time.now.monday.to_s(:db)], :order => ["cuenta DESC"], :limit => 3)
    
    if regalos.length < 3
      regalos = find(:all, :select => 'COUNT(*) as cuenta, tipo_regalo_id', :group => 'tipo_regalo_id', 
                     :conditions => ["created_at between ? and ?", (Time.now.monday - 7.days).to_s(:db), Time.now.monday.to_s(:db)], 
                     :order => ["cuenta DESC"], :limit => 3)
                     
      total = count(:conditions => ["created_at between ? and ?", (Time.now.monday - 7.days).to_s(:db), Time.now.monday.to_s(:db)])
      tipo = "anterior_semana"
    else
      total = count(:conditions => ["created_at > ?", Time.now.monday.to_s(:db)])
      tipo = "esta_semana"
    end    
    
    {:regalos => regalos, :total => total, :tipo => tipo}
  end

protected

  ## Callbacks ##
  def crea_evento_nuevo_regalo
    Evento.create(:usuario => invitado, :regalo_id => self.id, :tipo => "rn-recibido") if invitado
  end

  def crea_evento_aceptado_rechazado # Para los regalos aceptados/rechazados
    Evento.create(:usuario => remitente, :regalo_id => self.id, :tipo => "rn-#{self.state}") if ["expirado", "pendiente"].not.include? self.state
  end
  ## /Callbacks ##  
  
  # Acción diaria periódica
  def self.actualiza_estado_expirado_regalos
    regalos = Regalo.find(:all, :conditions => ["state = ? and fecha_terminado < ?", 'pendiente', Time.now])
    
    regalos.each do |regalo|
      regalo.expirar!
      RegaloMailer.deliver_aviso_regalo_cambio_estado(regalo, "invitado")
      RegaloMailer.deliver_aviso_regalo_cambio_estado(regalo, "remitente")
      Evento.create(:usuario => regalo.invitado, :regalo => regalo, :tipo => "rn-expiradoi")
      Evento.create(:usuario => regalo.remitente, :regalo => regalo, :tipo => "rn-expirador")
    end
    
    return regalos.length
  end
   
  # Acción diaria periódica 
  def self.avisa_48_horas_expirado_regalos
    regalos = Regalo.find(:all, :conditions => ['state = ? AND fecha_terminado BETWEEN ? AND ?', "pendiente", 
                                                 Time.now - 2.days - 5.minutes, Time.now - 2.days])
    
    regalos.each do |regalo|
      RegaloMailer.deliver_aviso_regalo_cambio_estado(regalo, "invitado")
      RegaloMailer.deliver_aviso_regalo_cambio_estado(regalo, "remitente")
      Evento.create(:usuario => regalo.invitado, :regalo => regalo, :tipo => "rn-expirado48i")
      Evento.create(:usuario => regalo.remitente, :regalo => regalo, :tipo => "rn-expirado48r")
    end
    
    return regalos.length
  end
end
